package compilador.gerador;

import java.util.Collection;

import compilador.semantico.Atributo;
import compilador.semantico.Metodo;
import compilador.semantico.Tipo;
import compilador.semantico.TabelaSemantica.TiposPrimitivo;

public class ClasseCodigo {

	private static final String CLASS_EXTENSION = ".java";
	private static final String CLASS_WORD = "class";
	private static final String EXTENDS_WORD = "extends";
	private static final String ARRAY_WORD = "[]";
	private static final String VOID_WORD = "void";
	private static final String NULL_RETURN_WORD = "\t\treturn null;";
	private static final char SPACE = ' ';
	private static final char OPEN_BRACE = '{';
	private static final char CLOSE_BRACE = '}';
	private static final char OPEN_PAREN = '(';
	private static final char CLOSE_PAREN = ')';
	private static final char NEW_LINE = '\n';
	private static final char TAB = '\t';
	private static final char END_COMMAND = ';';
	private static final char COMMA = ',';
	
	private String filename;
	private StringBuilder buffer = new StringBuilder();
	private int invNumber = 0;
	
	public ClasseCodigo(Tipo tipo) {
		this.filename = tipo.getNome() + CLASS_EXTENSION;
		init(tipo);
	}

	public String getFilename() {
		return this.filename;
	}
	
	private void init(Tipo tipo) {
		generateHeader(tipo);
		generateAtts(tipo.getAtributos());
		generateMetodos(tipo.getMetodos());
	}

	private void generateMetodos(Collection<Metodo> metodos) {
		for(Metodo met: metodos) {
			boolean hasReturn = true;
			buffer.append(TAB);
			String nomeTipo = met.getTipo();
			// tipo de retorno
			if( nomeTipo.equals(TiposPrimitivo.Void.name()) ){
				hasReturn = false;
				buffer.append(VOID_WORD);
			} else {
				buffer.append(nomeTipo);
			} 
			buffer.append(SPACE);
			buffer.append(met.getNome());
			buffer.append(OPEN_PAREN);
			// parametros
			int numParams = met.getNumParametros();
			for(int i = 1; i <= numParams; i++) {
				Atributo att = met.getParametro(i);
				buffer.append(att.getTipo());
				if (att.ehColecao()) {
					buffer.append(ARRAY_WORD);
				}
				buffer.append(SPACE);
				buffer.append(att.getNome());
				if (i < (numParams) ) {
					buffer.append(COMMA);
					buffer.append(SPACE);
				}
			}
			
			buffer.append(CLOSE_PAREN);
			buffer.append(OPEN_BRACE);
			buffer.append(NEW_LINE);
			if( hasReturn ) {
				buffer.append(NULL_RETURN_WORD);
				buffer.append(NEW_LINE);
			}
			buffer.append(TAB);
			buffer.append(CLOSE_BRACE);
			buffer.append(NEW_LINE);
		}
	}
	

	private void generateAtts(Collection<Atributo> atributos) {
		for(Atributo att : atributos) {
			buffer.append(TAB);
			buffer.append(att.getTipo());
			if (att.ehColecao()) {
				buffer.append(ARRAY_WORD);
			}
			buffer.append(SPACE);
			buffer.append(att.getNome());
			buffer.append(END_COMMAND);
			buffer.append(NEW_LINE);
		}
	}

	private void generateHeader(Tipo tipo) {
		buffer.append(CLASS_WORD);
		buffer.append(SPACE);
		buffer.append(tipo.getNome());
		buffer.append(SPACE);
		if (!tipo.getNome().equals(tipo.getTipo())) {
			buffer.append(EXTENDS_WORD);
			buffer.append(SPACE);
			buffer.append(tipo.getTipo());
			buffer.append(SPACE);
		}
		buffer.append(OPEN_BRACE);
		buffer.append(NEW_LINE);
	}

	public void addInv(String inv) {
		buffer.append(inv);
	}
	
	public void addInvBody(String body) {
		int index = buffer.indexOf("#");
		buffer.deleteCharAt(index);
		buffer.insert(index, body);		
	}

	
	public String getCode() {
		buffer.append(CLOSE_BRACE);
		return buffer.toString();
	}

	public String getNextInvNumber() {
		return Integer.toString(++invNumber);
	}



}

